﻿using System;
using System.DHTML;

namespace Saltarelle.UI {
	/// <summary>
	/// This interface identifies a source element for a drag-drop operation. See <see cref="IDropTarget"/> for more information.
	/// </summary>
	public interface IDragSource {
		/// <summary>
		/// Called to create the helper for a drag-drop operation.
		/// </summary>
		/// <param name="data">Data for the item being dragged. Will be one of the objects registered by the <see cref="ISaltarelleUIService.MakeDraggable"/> method.</param>
		/// <returns>An element to use as a helper, or null to use a clone of the element being dragged.</returns>
		DOMElement CreateDragHelper(object data);

		/// <summary>
		/// Called when a drag operation is initiated.
		/// </summary>
		/// <param name="data">Data for the item being dragged. Will be one of the objects registered by the <see cref="ISaltarelleUIService.MakeDraggable"/> method.</param>
		/// <param name="helper">Draggable helper.</param>
		void DragStarted(object data, DOMElement helper);
		
		/// <summary>
		/// Called to give the source the final saying about what a drag effect should be.
		/// </summary>
		/// <param name="target">The target on which the dragged element was dropped.</param>
		/// <param name="sourceData">Data that is being dragged.</param>
		/// <param name="targetData">Data acquired from the <see cref="IDropTarget.DragOver"/> method for the target.</param>
		/// <returns>Whether the drop is allowed.</returns>
		bool QueryDrop(IDropTarget target, object sourceData, object targetData);
		
		/// <summary>
		/// Called when a drag-drop operation was cancelled.
		/// </summary>
		/// <param name="data">Data for the dragged object.</param>
		void DragDropCancelled(object data);

		/// <summary>
		/// Called after a drop has occurred.
		/// </summary>
		/// <param name="target">Target of the drop operation.</param>
		/// <param name="sourceData">Data that is being dragged.</param>
		/// <param name="targetData">Drop data from the <see cref="IDropTarget.DragOver"/> method.</param>
		void DragDropCompleted(IDropTarget target, object sourceData, object targetData);
	}
	
	/// <summary>
	/// This interface identifies a possible target for a drag-drop operation. The sequence of a drag-drop operation is as follows:<br/>
	///           Drop target calls <see cref="ISaltarelleUIService.RegisterDropTarget"/> when it is rendered.<br/>
	///           Drag source calls <see cref="ISaltarelleUIService.MakeDraggable"/> for each draggable element (eg. when an element is selected).<br/>
	///           User initiates drag-drop operation.
	///                                        +---------------------------------------&lt;----------------------------------------+
	///           IDragSource.DragDropStarted -+-> IDropTarget.DragEnter -+->- IDropTarget.DragOver -+->-+- IDropTarget.DragLeave -+- IDropSource.DragDropCancelled -> Done.
	///                                                                   +-----------&lt;-----------+   +- IDropSource.QueryDrop ->-+- IDropTarget.Drop ->- IDropSource.DragDropCompleted ->- Done.
	/// </summary>
	public interface IDropTarget {
		/// <summary>
		/// Called when an item is being dragged over a target.
		/// </summary>
		/// <param name="dragSource">Source of the drag operation.</param>
		/// <param name="sourceData">Data for the element being dragged.</param>
		void DragEnter(IDragSource dragSource, object sourceData);
		
		/// <summary>
		/// Called when an item is being dragged over a target.
		/// </summary>
		/// <param name="dragSource">Source of the drag operation.</param>
		/// <param name="sourceData">Data for the element being dragged.</param>
		/// <param name="cursorPos">Cursor position, relative to the drop target's registered element and adjusted for any scrolling.</param>
		/// <returns>An object with data about the drop target, or null if the drop is not allowed.</returns>
		object DragOver(IDragSource dragSource, object sourceData, LeftTop cursorPos);
		
		/// <summary>
		/// Called when a dragged element leaves a target without dropping.
		/// </summary>
		/// <param name="dragSource">Source of the drag operation.</param>
		/// <param name="sourceData">Data for the object that leaves the drop area.</param>
		void DragLeave(IDragSource dragSource, object sourceData);
		
		/// <summary>
		/// Drop an element.
		/// </summary>
		/// <param name="dragSource">Source of the drag operation.</param>
		/// <param name="sourceData">Data for the dragged object.</param>
		/// <param name="targetData">Data returned by the last <see cref="DragOver"/> call.</param>
		/// <param name="cursorPos">Cursor position of the drop.</param>
		void Drop(IDragSource dragSource, object sourceData, object targetData, LeftTop cursorPos);
	}
}
